﻿using System;
using System.Windows.Forms;
using GACore;
using GACore.ReversiGA;

namespace Reversi
{
	public partial class FormOptimization : Form
	{
		private ReversiGAMapper reversiGAMapper;
		private Preferences gaPreferences;

		private bool isOptimizationFinished = false;

		public FormOptimization(ReversiGAMapper reversiGAMapper, Preferences gaPreferences)
		{
			this.reversiGAMapper = reversiGAMapper;
			this.gaPreferences = gaPreferences;

			GACore.Controller.Instance.StepComputed += GAController_StepComputed;

			InitializeComponent();
		}

		private void FormOptimization_Load(object sender, EventArgs e)
		{
			this.Controls.Remove(lblCancel);
			saveFileDialog1.Filter = "XML (*.xml)|*.xml";
			Optimize();
		}

		private void GAController_StepComputed(object sender, StepComputedEventArgs e)
		{
			if (reversiGAMapper.GaPreferences.OptimizationSteps != progressBar1.Maximum)
			{
				SetProgressMax(reversiGAMapper.GaPreferences.OptimizationSteps);
			}
			PerformStepOnProgress();
		}

		private delegate void OptimizationFinishedCallbackCallback(IAsyncResult asyncResult);
		private void OptimizationFinishedCallback(IAsyncResult asyncResult)
		{
			if (this.InvokeRequired)
			{
				this.Invoke(new OptimizationFinishedCallbackCallback(OptimizationFinishedCallback), asyncResult);
			}
			else
			{
				if (isOptimizationFinished)
				{
					return;
				}
				isOptimizationFinished = true;

				var asyncState = (AsyncState)asyncResult.AsyncState;
				var del = (Func<OptimizationFinishedArgs>)asyncState.Del;
				var optimizationFinishedArgs = del.EndInvoke(asyncResult);

				string filename = optimizationFinishedArgs.Directory + "/NeuralNet.xml";

				if (ErrorHandler.ShowQuestion(optimizationFinishedArgs.ResultString + Environment.NewLine +
					"Möchten Sie das neuronale Netz im gleichen Ordner speichern?", "Optimierung abgeschlossen") == DialogResult.No)
				{
					if (saveFileDialog1.ShowDialog() == DialogResult.OK)
					{
						filename = saveFileDialog1.FileName;
					}
				}
				NNCore.Controller nnController = new NNCore.Controller(filename, optimizationFinishedArgs.BestResult);
				nnController.Save();
				this.Close();
			}
		}

		private void btnCancel_Click(object sender, EventArgs e)
		{
			GACore.Controller.Instance.CancelOptimization();
			if (!this.Controls.Contains(lblCancel))
			{
				this.Controls.Add(lblCancel);
			}
		}

		private void Optimize()
		{
			try
			{
				reversiGAMapper.BeginStart(OptimizationFinishedCallback, reversiGAMapper);
			}
			catch (Exception e)
			{
				ErrorHandler.ShowError(e.Message, "Fehler während der Optimierung");
			}
		}

		private void RunsOnWorkerThread() { reversiGAMapper.Start(); }

		private delegate void SetProgressMaxCallback(int max);
		private void SetProgressMax(int max)
		{
			if (InvokeRequired)
			{
				this.Invoke(new SetProgressMaxCallback(SetProgressMax), max);
			}
			else
			{
				progressBar1.Maximum = max;
			}
		}

		private delegate void PerformStepOnProgressCallback();
		private void PerformStepOnProgress()
		{
			if (InvokeRequired)
			{
				this.Invoke(new PerformStepOnProgressCallback(PerformStepOnProgress));
			}
			else
			{
				progressBar1.PerformStep();
				lblOptimizationCount.Text = GACore.Controller.Instance.CurrentOptimizationCount + "/" + gaPreferences.OptimizationSteps;
			}
		}

	}
}
